# Main UI for Gupicasa
#
# Copyright (C) 2010 Yotam Medini <yotam.medini@gmail.com>
#
# This file is part of Gupicasa.
#
# Gupicasa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Gupicasa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gupicasa.  If not, see <http://www.gnu.org/licenses/>.


import gtk
import os
import sys
import time

# local
import debug
import led
import ped
import pref
import ugtk
import uicommon
import ver


class UI:


    def __init__(self, parent=None):
        debug.log("parent=%s" % parent)
        gtk.gdk.threads_init()
        self.connect_time_widgets = []
        self.disconnect_time_widgets = []
        self.parent = parent
        self.common = uicommon.Common()
        self.create_ui()
        self.topwin.show_all()
        self.set_sensitivity(connected=False)
        self.set_mode(w=None, local=True)
        gtk.gdk.threads_enter()
        gtk.main()
        gtk.gdk.threads_leave()


    def create_ui(self):
        self.ui = gtk.UIManager()
        self.about_dialog = None
        self.topwin = topwin = gtk.Window()
        self.common.topwin = topwin
        topwin.set_icon(self.common.icons_pixbuf["gupicasa"])
        topwin.set_size_request(800, 600)
        topwin.connect('delete-event', self.quit)
        topwin.set_title("Gupicasa - Upload tool to Picasa")
        vbox = gtk.VBox()
        topwin.add(vbox)
        vbox.pack_start(self.create_menubar(topwin), False, False, 0)
        vbox.pack_start(self.control_box(), False, False, 2)
        self.local_page = self.create_local_page()
        self.picasa_page = self.create_picasa_page()
        vbox.pack_start(self.local_page, True, True, 0)
        vbox.pack_start(self.picasa_page, True, True, 0)
        vbox.pack_end(self.common.statusbar, expand=False, fill=False,
                      padding=1)
        ugtk.uimgr_set_tips(self.ui)
        return topwin


    def create_menubar(self, topwin):
        debug.log("")
        entries = (
            ( "FileMenu", None, "_File" ),
            ( "EditMenu", None, "_Edit" ),
            ( "OptionsMenu", None, "_Options" ),
            ( "PreferencesMenu", None, "_Preferences" ),
            ( "HelpMenu", None, "_Help" ),
            ( "Open", gtk.STOCK_OPEN,
              "_Open","<control>O",
              "Open local directory",
              self.local_page_open),
            ( "Connect", "picasa-logo",
              "_Picasa","<control>P",
              "Connect to Picasa account",
              self.picasa_connect),
            ( "Disconnect", gtk.STOCK_DISCONNECT,
              "_Disconnect", None,
              "Disconnect from Picasa account",
              self.picasa_disconnect),
            ( "Upload", gtk.STOCK_GO_UP,
              "_Upload", None,
              "Upload selected local pictures\n" +
              "to current Picasa album",
              self.upload),
            ( "Quit", gtk.STOCK_QUIT,
              "_Quit", "<control>Q",
              "Quit",
              self.quit),

            ( "Preferences", gtk.STOCK_PREFERENCES,
              "_Preferences", None,
              "Set preferences",
              self.preferences),

            ( "About", None,
              "_About", "<control>A",
              "About this application",
              self.about),
            )

        toggle_entries = (
            (
                "Debug", None,
                "Debug", None,
                "Allow debug print to stderr",
                self.debug_activate,
                debug.debug_on),
            )

        ui_info = \
'''<ui>
  <menubar name='MenuBar'>
    <menu action='FileMenu'>
      <menuitem action='Open'/>
      <menuitem action='Connect'/>
      <menuitem action='Disconnect'/>
      <menuitem action='Upload'/>
      <separator/>
      <menuitem action='Quit'/>
    </menu>
    <menu action='EditMenu'>
    </menu>
    <menu action='OptionsMenu'>
      <menuitem action='Debug'/>
      <menuitem action='Preferences'/>
    </menu>
    <menu action='HelpMenu'>
      <menuitem action='About'/>
    </menu>
  </menubar>
  <toolbar  name='ToolBar'>
    <toolitem action='Open'/>
    <toolitem action='Quit'/>
  </toolbar>
</ui>'''


        self.actions = actions = gtk.ActionGroup("Actions")
        actions.add_actions(entries)
        actions.add_toggle_actions(toggle_entries)

        ui = self.ui
        ui.insert_action_group(actions, 0)
        topwin.add_accel_group(ui.get_accel_group())
        mergeid = ui.add_ui_from_string(ui_info)
        mb = ui.get_widget("/MenuBar")
        # mb.set_tooltips(True)
        mb.show_all()
        actions_paths = ugtk.ui_get_action_paths(ui_info)
        for p in actions_paths:
            widget = ui.get_widget(p)
            if widget is not None:
                if p.find("/Connect") >= 0:
                    self.disconnect_time_widgets.append(widget)
                elif p.find("/Disconnect") >= 0:
                    self.connect_time_widgets.append(widget)
        return mb


    def control_box(self):
        ctl_box = gtk.HBox()
        f = gtk.Frame("Mode")
        hbox_mode = gtk.HBox()

        b = ugtk.StockButton(gtk.STOCK_HARDDISK, "Local")
        b.connect('clicked', self.set_mode, True)
        hbox_mode.pack_start(b, expand=False, fill=False, padding=0)

        b = ugtk.StockButton("picasa-logo", "Picasa")
        b.connect('clicked', self.set_mode, False)
        hbox_mode.pack_start(b, expand=False, fill=False, padding=0)

        f.add(hbox_mode)
        ctl_box.pack_start(f, expand=False, fill=False, padding=12)

        self.local_control_frame = gtk.Frame("")
        self.picasa_control_frame = gtk.Frame("Picasa")
        for (f, stock, label) in (
            (self.local_control_frame, gtk.STOCK_HARDDISK, "Local"),
            (self.picasa_control_frame, "picasa-logo", "Picasa")):

            hb = gtk.HBox()
            hdimg = gtk.Image()
            hdimg.set_from_stock(stock, gtk.ICON_SIZE_BUTTON)
            hb.pack_start(hdimg, False, False, padding=2)
            hb.pack_start(gtk.Label(label), False, False, padding=2)
            hb.show_all()
            f.set_label_widget(hb)
            f.add(gtk.HBox()) # The one and only child
            ctl_box.pack_start(f, expand=False, fill=False, padding=12)

        b = ugtk.StockButton(gtk.STOCK_GO_UP, "Upload")
        b.set_tooltip_text(self.actions.get_action('Upload').get_tooltip())
        b.connect('clicked', self.upload)

        # ctl_box.pack_start(b, expand=False, fill=False, padding=12)
        ugtk.pack_start_align(ctl_box, b, ugtk.ALIGN_CENTER,
                              expand=False, fill=False, padding=12)

        return ctl_box


    def create_local_page(self):
        debug.log("")
        vbox = gtk.VBox()
        b = ugtk.StockButton(gtk.STOCK_DIRECTORY)
        b.set_tooltip_text("Open local directory")
        b.connect('clicked', self.local_page_open)
        fhbox = self.local_control_frame.get_child()
        fhbox.pack_start(b, expand=False, fill=False, padding=1)
        cmdbox = self.local_control_frame.get_child()
        self.imgdired = led.ImgDirEditor(
            self.ui, cmdbox=cmdbox, common=self.common)
        vbox.pack_start(self.imgdired.mainwin, expand=True, fill=True,
                        padding=4)
        return vbox


    def local_page_open(self, w):
        debug.log("")
        dlg = gtk.FileChooserDialog(
            title="Select local directory of photos",
            parent=self.topwin,
            action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
            buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                     gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        response = dlg.run()
        debug.log("response=%d" % response)
        dn = None
        if response == gtk.RESPONSE_OK:
            dn = dlg.get_current_folder()
            debug.log("dn=%s" % dn)
        dlg.destroy()
        if dn is not None:
            self.imgdired.opendir(dn)


    def create_picasa_page(self):
        debug.log("")
        fhbox = self.picasa_control_frame.get_child()

        b = ugtk.StockButton(gtk.STOCK_CONNECT, "Connect")
        b.connect('clicked', self.picasa_connect)
        b.set_tooltip_text("Connect to Picasa account")
        self.disconnect_time_widgets.append(b)
        fhbox.pack_start(b, expand=False, fill=False, padding=2)

        b = ugtk.StockButton(gtk.STOCK_DISCONNECT, "Disconnect")
        b.connect('clicked', self.picasa_disconnect)
        b.set_tooltip_text("Disconnect from Picasa account")
        self.connect_time_widgets.append(b)
        fhbox.pack_start(b, expand=False, fill=False, padding=2)

        vbox = gtk.VBox()
        self.picasa_editor = ped.PicasaEditor(self)
        vbox.pack_start(self.picasa_editor.mainwin, expand=True, fill=True,
                        padding=4)
        return vbox


    def set_sensitivity(self, connected):
        for w in self.connect_time_widgets:
            w.set_sensitive(connected)
        for w in self.disconnect_time_widgets:
            w.set_sensitive(not connected)


    #############
    # Callbacks #


    def quit(self, w=None, data=None):
        debug.log("")
        if self.parent is not None:
            self.parent.logout()
        gtk.main_quit()


    def set_mode(self, w, local):
        debug.log("local=%s" % local)
        ugtk.show_flag_widgets(local,
                               (self.local_page, self.local_control_frame))
        ugtk.show_flag_widgets(not local,
                               (self.picasa_page, self.picasa_control_frame))
        self.imgdired.on_focus(local)
        self.picasa_editor.on_focus(not local)


    def picasa_connect(self, w):
        debug.log("")
        flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT
        dlg = gtk.Dialog(title="Login to Picasa account",
                         parent=self.topwin, flags=flags,
                         buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
                                  gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
        stock = gtk.image_new_from_stock(gtk.STOCK_DIALOG_AUTHENTICATION,
                                         gtk.ICON_SIZE_DIALOG)

        hb_main = gtk.HBox()
        hb_main.pack_start(stock, False, False, 0)
        unpw = gtk.Table(2, 2)
        eun = gtk.Entry()
        epw = gtk.Entry()
        eun.set_tooltip_text("Enter your Picasa's user-name.\n" +
                             "The '@gmail.com' suffix is not needed")
        epw.set_visibility(False)
        parent = self.parent
        if parent is not None:
            if parent.uname is not None:
                eun.set_text(parent.uname)
            if parent.password is not None:
                epw.set_text(parent.password)
        ugtk.attach1(unpw, gtk.Label("Usarname:"), 0, 0, xoptions=0);
        ugtk.attach1(unpw, eun, 1, 0);
        ugtk.attach1(unpw, gtk.Label("Password:"), 0, 1, xoptions=0);
        ugtk.attach1(unpw, epw, 1, 1);
        hb_main.pack_start(unpw, expand=True, fill=True, padding=6)
        dlg.vbox.pack_start(hb_main)
        dlg.show_all()
        response = dlg.run()
        connected = False
        if parent is not None:
            while response == gtk.RESPONSE_OK and not connected:
                parent.uname = eun.get_text()
                parent.password = epw.get_text()
                debug.log("un=%s, pw=%s" % (parent.uname, parent.password))
                connected = parent.login()
                if not connected:
                    self.warning("Login failed")
                    time.sleep(1)
                    response = dlg.run()
        dlg.destroy()
        if connected:
            self.picasa_editor.set_albums_menu()
        self.set_sensitivity(connected)
        self.picasa_editor.update_status()


    def picasa_disconnect(self, w):
        debug.log("")
        self.parent.logout()
        self.set_sensitivity(False)
        self.picasa_editor.update_status()


    def upload(self, w):
        debug.log("")
        confirmed = False
        (n_sel, n_mod, n_cap, n_dirty) = self.imgdired.get_selection_numbers()
        if n_sel == 0:
            self.warning("No local photos selected")
        elif self.parent.service is None:
            self.warning("Please connect to Picasa\n" +
                         "and select an album")
        elif self.picasa_editor.current_album_id is None:
            self.warning("Please select a Picasa album")
        else:
            photo_photos = "photo"   if n_sel == 1 else "photos"
            is_are       = "is"      if n_mod == 1 else "are"
            has_have     = "has"     if n_cap == 1 else "have"
            caption_s    = "caption" if n_cap == 1 else "captions"

            confirm_text = """
You are about to upload
<b>%3d</b> local %s to current Picasa album.
Out of which:
  <b>%3d</b> %s locally modified by this application
  <b>%3d</b> %s %s added by this application.
"""[1:] % (n_sel, photo_photos,
           n_mod, is_are,
           n_cap, has_have, caption_s)

        if n_dirty > 0:
            confirm_text += """
<b><span foreground="red">
   Non saved modifications of
   %d photo%s
   will be ignored for upload.
</span></b>
""" % (n_dirty, "s" if n_dirty > 1 else "")
        confirmed = self.confirm(markup=confirm_text)
        debug.log("confirmed=%d" % confirmed)
        if confirmed:
            n_uploaded = [0, n_sel]
            # self.imgdired.for_selected(self.upload_edimg, n_uploaded)
            self.imgdired.upload(self.upload_edimg, n_uploaded)
            self.common.statusbar.set_text("Done uploading %d photos" %
                                           n_uploaded[0])
            self.picasa_editor.set_current_album_photos()


    def upload_edimg(self, ed_img, n_uploaded):
        n_uploaded[0] += 1
        album_id = self.picasa_editor.current_album_id
        fn = ed_img.saved_filename
        if fn is None:
            fn = ed_img.filename
        self.common.statusbar.set_text("Uploading %d/%d %s" %
                                       (n_uploaded[0], n_uploaded[1], fn))
        self.parent.put_photo(album_id, fn, ed_img.caption)


    def preferences(self, w):
        debug.log("")
        dlg = pref.PreferencesDialog(
            prefs=self.common.preferences,
            parent=self.topwin,
            icon=self.common.icons_pixbuf["gupicasa"])
        dlg.xrun()
        dlg.destroy()


    def debug_activate(self, action):
        debug.log("active=%s" % action.get_active())
        debug.debug_on = action.get_active()


    def about(self, w):
        debug.log("")
        dialog = self.about_dialog
        if dialog is None:
            debug.log("Create new AboutDialog")
            self.about_dialog = dialog = gtk.AboutDialog()
            dialog.set_name("Gupicasa - Uploader to Picasa")
            dialog.set_version(ver.str_version)
            dialog.set_logo(self.common.icons_pixbuf["gupicasa"]) # Inside
            dialog.set_icon(self.common.icons_pixbuf["gupicasa"]) # for Win-Mgr
            dialog.set_copyright("Yotam Medini")
            dialog.set_website("http://code.google.com/p/gupicasa/")
            dialog.set_license("GPLv3")
            dialog.set_authors(["Yotam Medini <yotam.medini@gmail.com>"])
            dialog.connect ("delete-event", self.about_cb, "delete")
            dialog.connect ("destroy-event", self.about_cb, "destroy")
        dialog.show_all()
        dialog.run()
        dialog.hide()


    def about_cb(self, w, e, s):
        debug.log("w=%s, e=%s, s=%s" % (w, e, s))
        w.hide()
        return True


    def confirm(self, message=None, markup=None):
        flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT
        dlg = gtk.MessageDialog(parent=self.topwin, flags=flags,
                                type=gtk.MESSAGE_QUESTION,
                                buttons=gtk.BUTTONS_OK_CANCEL,
                                message_format=message)
        if markup is not None:
            dlg.set_markup(markup)
        dlg.set_icon(self.common.icons_pixbuf["gupicasa"])
        dlg.show()
        response = dlg.run()
        dlg.destroy()
        debug.log("response=%d (ok=%d, cancel=%d)" %
                  (response, gtk.RESPONSE_OK, gtk.RESPONSE_CANCEL))
        return (response == gtk.RESPONSE_OK)


    def warning(self, message):
        ugtk.warning(self.topwin, message)


if __name__ == '__main__':
    debug.log("begin")
    ui = UI()
    debug.log("end")
    sys.exit(0)
